今天要來接紹一個還在實驗性的hook,只有在實驗性和canary的版本才有支援。
這個hook的功能是用來讀取資源的值,這邊的資源可以是Promise和context兩種類型的資源。這個hook有一個跟其他hook不同的特點就是可以用在條件和迴圈裏面。
const value = use(resource);
resource
可以分為兩種Promise和context,先從較單純的context開始介紹
用法和useContext
雷同,useContext(SomeContext)
變成use(SomeContext)
回傳的一樣是context的值,不同的是use
可以使用在條件和迴圈裡面,比useContext
用起來更靈活。
import { createContext, use } from "react";
export const TextContext = createContext();
function Content({name, show}) {
if (show) {
const val = use(TextContext); // 可以使用在條件裡
return <>
<h2>{val} {name}</h2>
</>
}
return <h3>{name}</h3>
}
function ContentWrap({children}) {
return <div>
<h1>ContentWrap</h1>
{children}
</div>
}
function App() {
return (
<TextContext.Provider value={"哈囉"}>
<ContentWrap>
<Content show={true} name="小明" />
<Content show={false} name="小美" />
</ContentWrap>
</TextContext.Provider>
);
}
export default App;
這邊的use
裡面接著一個fetch promise,然後搭配內建的Suspense
元件使用。在use
還在載入的時候會顯示fallback
prop帶入的內容,等載入好就會顯示裡面的chidren
,在下面這個範例就是Message元件。
function Message({ messagePromise }) {
// 這個messagePromise就是fetchMessage return的fetch promise
const messageContent = use(messagePromise);
return <>
<p>Here is the message:</p>
<img src={messageContent} />
</>
}
function MessageContainer({ messagePromise }) {
return (
<Suspense fallback={<p>⌛Downloading message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}
function fetchMessage() {
return fetch("https://dog.ceo/api/breeds/image/random") // 這邊找一個很可愛狗圖庫的api當範例
.then((response) => response.json())
.then((data) => data.message);
}
export default function App() {
const [messagePromise, setMessagePromise] = useState(null);
const [show, setShow] = useState(false);
function download() {
setMessagePromise(fetchMessage());
setShow(true);
}
if (show) {
return <MessageContainer messagePromise={messagePromise} />;
} else {
return <button onClick={download}>Download message</button>;
}
}
如果promise失敗可以用兩種方式處理
在fetch最後加上個catch
function fetchMessage() {
return fetch("https://dog.ceo/api/breeds/image/random")
.then((response) => response.json())
.then((data) => data.message)
.catch(() => {
return "no new message found.";
})
}
function Message({ messagePromise }) {
const messageContent = use(messagePromise);
console.log(messageContent);
// 畫面呈現可以加個小判斷
return <>
<p>Here is the message:</p>
{
messageContent.match(/^http/)
? <img src={messageContent} alt="" />
: messageContent
}
</>
}
可以直接使用**react-error-boundary不用自己寫class**
直接在最外層再包一層ErrorBoundary元件,將要顯示的錯誤畫面加入fallback屬性,可以看官網範例。我自己是用vite專案似乎會有與react版本會有些問題,無法使用。
export function MessageContainer({ messagePromise }) {
return (
<ErrorBoundary fallback={<p>⚠️Something went wrong</p>}>
<Suspense fallback={<p>⌛Downloading message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
</ErrorBoundary>
);
}
https://react.dev/reference/react/use